#include "lib/pvmsystem.h"
#include "lib/pvmstrings.h"
#include "lib/memory/pvmmemory.h"
#include "lib/pvmdebug.h"

#define DBG_MON_MAX_PARAMS	256

struct DbgMonHandlers
{
	TDebugMonitorParameterRegisterHandler registerHandler;
	TDebugMonitorParameterUnregisterHandler unregisterHandler;
	TDebugMonitorParameterUpdateHandler updateHandler;
};

class DbgMonParameterInfo
{
private:
	pvm_bool used;
	pvm_char name[PVM_DEBUG_PARAM_NAME_MAX_LENGTH + 1];
	TPVMDebugParamType paramType;
	TPVMDebugParamValue minValue;
	TPVMDebugParamValue maxValue;
	TPVMDebugParamValue currentValue;

	TPVMDebugParamValue reportedMinValue;
	TPVMDebugParamValue reportedMaxValue;
public:
	DbgMonParameterInfo() {used = false; name[0] = 0;}

	pvm_bool isUsed() {return used;} 
	pvm_bool init(const pvm_char* name, TPVMDebugParamType paramType, TPVMDebugParamValue minValue, TPVMDebugParamValue maxValue, TPVMDebugParamValue currentValue);
	void deinit();

	void update(TPVMDebugParamValue currentValue);

	const pvm_char* getName() {return name;}
	TPVMDebugParamType getParamType() {return paramType;}
	TPVMDebugParamValue getMinValue() {return minValue;}
	TPVMDebugParamValue getMaxValue() {return maxValue;}
	TPVMDebugParamValue getCurrentValue() {return currentValue;}
	TPVMDebugParamValue getReportedMinValue() {return reportedMinValue;}
	TPVMDebugParamValue getReportedMaxValue() {return reportedMaxValue;}
};

pvm_bool DbgMonParameterInfo::init(const pvm_char* name, TPVMDebugParamType paramType, TPVMDebugParamValue minValue, TPVMDebugParamValue maxValue, TPVMDebugParamValue currentValue)
{
	if(used)
		return false;

	if(pvm_strlen(name) > PVM_DEBUG_PARAM_NAME_MAX_LENGTH)
		return false;

	pvm_strcpy(this->name, name);
	this->paramType = paramType;
	this->minValue = minValue;
	this->maxValue = maxValue;
	this->currentValue = currentValue;
	reportedMinValue = maxValue;
	reportedMaxValue = minValue;
	used = true;

	return true;
}

void DbgMonParameterInfo::deinit()
{
	used = false;
}

void DbgMonParameterInfo::update(TPVMDebugParamValue currentValue)
{
	if(!used)
		return;
	this->currentValue = currentValue;
	switch(paramType)
	{
		case EPVM_TYPE_INT:
			{
				if(currentValue.iParam > reportedMaxValue.iParam)
					reportedMaxValue = currentValue;
				else if(currentValue.iParam < reportedMinValue.iParam)
					reportedMinValue = currentValue;
			}
			break;
		case EPVM_TYPE_UINT:
			{
				if(currentValue.uParam > reportedMaxValue.uParam)
					reportedMaxValue = currentValue;
				else if(currentValue.uParam < reportedMinValue.uParam)
					reportedMinValue = currentValue;
			}
			break;
		case EPVM_TYPE_FLOAT:
			{
				if(currentValue.fParam > reportedMaxValue.fParam)
					reportedMaxValue = currentValue;
				else if(currentValue.fParam < reportedMinValue.fParam)
					reportedMinValue = currentValue;
			}
			break;
	}
}

//////////////////////////////////////////////////////////////////////////
//
//////////////////////////////////////////////////////////////////////////

static DbgMonHandlers dbgMonHandlers = {NULL, NULL, NULL};
pvm_bool dbgMonInitialized = false;

DbgMonParameterInfo	dbgMonParameters[DBG_MON_MAX_PARAMS];

void PVMDebugMonitorInit()
{
	dbgMonInitialized = true;
}

void PVMDebugMonitorDeinit()
{
	dbgMonInitialized = false;
}

PVMAPI void PVMCALL PVMDebugMonitorRegisterEventHandler(TDebugMonitorParameterRegisterHandler registerHandler, TDebugMonitorParameterUnregisterHandler unregisterHandler, TDebugMonitorParameterUpdateHandler updateHandler)
{
	dbgMonHandlers.registerHandler = registerHandler;
	dbgMonHandlers.unregisterHandler = unregisterHandler;
	dbgMonHandlers.updateHandler = updateHandler;
}


PVMAPI pvm_int PVMCALL PVMDebugMonitorParameterRegister(const pvm_char* name, TPVMDebugParamType paramType, TPVMDebugParamValue minValue, TPVMDebugParamValue maxValue, TPVMDebugParamValue currentValue)
{
	pvm_int result = -1;

	for(pvm_int i=0; i<DBG_MON_MAX_PARAMS; i++)
	{
		if(dbgMonParameters[i].isUsed()==false)
		{
			if(dbgMonParameters[i].init(name, paramType, minValue, maxValue, currentValue))
			{
				result = i;
				if(dbgMonHandlers.registerHandler)
				{
					dbgMonHandlers.registerHandler(i, name, paramType, minValue, maxValue);
				}
			}
			break;
		}
	}

	return result;
}

PVMAPI void PVMCALL PVMDebugMonitorParameterUnregister(pvm_int paramId)
{
	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return;

	if(dbgMonParameters[paramId].isUsed()==false)
		return;

	pvm_char name[PVM_DEBUG_PARAM_NAME_MAX_LENGTH + 1];

	if(dbgMonHandlers.unregisterHandler)
	{
		pvm_strcpy(name, dbgMonParameters[paramId].getName());
	}

	dbgMonParameters[paramId].deinit();

	if(dbgMonHandlers.unregisterHandler)
	{
		dbgMonHandlers.unregisterHandler(paramId, name);
	}
}

PVMAPI pvm_bool PVMCALL PVMDebugMonitorParameterUpdate(pvm_int paramId, TPVMDebugParamValue currentValue)
{
	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return false;

	if(dbgMonParameters[paramId].isUsed()==false)
		return false;

	dbgMonParameters[paramId].update(currentValue);

	if(dbgMonHandlers.updateHandler)
	{
		dbgMonHandlers.updateHandler(paramId, dbgMonParameters[paramId].getName(), dbgMonParameters[paramId].getParamType(), dbgMonParameters[paramId].getMinValue(), dbgMonParameters[paramId].getMaxValue(), currentValue);
	}

	return true;
}

PVMAPI const pvm_char* PVMCALL PVMDebugMonitorGetParamName(pvm_int paramId)
{
	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return NULL;

	if(dbgMonParameters[paramId].isUsed()==false)
		return NULL;

	return dbgMonParameters[paramId].getName();
}

PVMAPI TPVMDebugParamType PVMCALL PVMDebugMonitorGetParamType(pvm_int paramId)
{
	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return (TPVMDebugParamType)-1;

	if(dbgMonParameters[paramId].isUsed()==false)
		return (TPVMDebugParamType)-1;

	return dbgMonParameters[paramId].getParamType();
}

PVMAPI TPVMDebugParam PVMCALL PVMDebugMonitorGetParamMaxValue(pvm_int paramId)
{
	TPVMDebugParam retVal;
	retVal.valid = false;

	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return retVal;

	if(dbgMonParameters[paramId].isUsed()==false)
		return retVal;

	retVal.type = dbgMonParameters[paramId].getParamType();
	retVal.value = dbgMonParameters[paramId].getMaxValue();

	retVal.valid = true;
	return retVal;
}

PVMAPI TPVMDebugParam PVMCALL PVMDebugMonitorGetParamMinValue(pvm_int paramId)
{
	TPVMDebugParam retVal;
	retVal.valid = false;

	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return retVal;

	if(dbgMonParameters[paramId].isUsed()==false)
		return retVal;

	retVal.type = dbgMonParameters[paramId].getParamType();
	retVal.value = dbgMonParameters[paramId].getMinValue();

	retVal.valid = true;
	return retVal;
}

PVMAPI TPVMDebugParam PVMCALL PVMDebugMonitorGetParamCurrentValue(pvm_int paramId)
{
	TPVMDebugParam retVal;
	retVal.valid = false;

	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return retVal;

	if(dbgMonParameters[paramId].isUsed()==false)
		return retVal;

	retVal.type = dbgMonParameters[paramId].getParamType();
	retVal.value = dbgMonParameters[paramId].getCurrentValue();

	retVal.valid = true;
	return retVal;
}

PVMAPI TPVMDebugParam PVMCALL PVMDebugMonitorGetParamReportedMaxValue(pvm_int paramId)
{
	TPVMDebugParam retVal;
	retVal.valid = false;

	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return retVal;

	if(dbgMonParameters[paramId].isUsed()==false)
		return retVal;

	retVal.type = dbgMonParameters[paramId].getParamType();
	retVal.value = dbgMonParameters[paramId].getReportedMaxValue();

	retVal.valid = true;
	return retVal;
}

PVMAPI TPVMDebugParam PVMCALL PVMDebugMonitorGetParamReportedMinValue(pvm_int paramId)
{
	TPVMDebugParam retVal;
	retVal.valid = false;

	if(paramId<0 || paramId>=DBG_MON_MAX_PARAMS)
		return retVal;

	if(dbgMonParameters[paramId].isUsed()==false)
		return retVal;

	retVal.type = dbgMonParameters[paramId].getParamType();
	retVal.value = dbgMonParameters[paramId].getReportedMinValue();

	retVal.valid = true;
	return retVal;
}